package 简单.树;

import util.TreeNode;

import java.util.*;

/**
 * 给定一个二叉搜索树 root 和一个目标结果 k，如果 BST 中存在两个元素且它们的和等于给定的目标结果，则返回 true。
 * <p>
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/two-sum-iv-input-is-a-bst/
 */
public class 两数之和IV输入BST_653 {

    public static void main(String[] args) {

        //[2,0,3,-4,1]

    }

    /**
     * 双指针+中序遍历
     * 一个指针指向首部，一个指针指向尾部
     * 如果两指针相加大于目标值，则尾部指针向前移一位
     * 如果两指针相加小于目标值，则首部指针向后移一位
     *
     * @param root
     * @param k
     * @return
     */
    public boolean findTarget(TreeNode root, int k) {
        List<Integer> list = new ArrayList<>();
        // 收集所有值
        collectValue(list, root);
        int left = 0;
        int right = list.size() - 1;
        while (left < right) {
            Integer curSum = list.get(left) + list.get(right);
            if (curSum == k) {
                return true;
            } else if (curSum > k) {
                right--;
            } else {
                left++;
            }
        }
        return false;
    }

    /**
     * 中序遍历可以使二叉搜索树升序排序
     * 题目值有负数，所以不需要过滤掉比k大的元素
     *
     * @param list
     * @param root
     */
    public void collectValue(List<Integer> list, TreeNode root) {
        if (root == null) {
            return;
        }
        collectValue(list, root.left);
        list.add(root.val);
        collectValue(list, root.right);
    }

    private Set<Integer> set = new HashSet<>();

    /**
     * 深度搜索+哈希表
     * 如果哈希表中有k-curValue，那么返回true
     * 否则将curValue添加到哈希表中
     *
     * @param root
     * @param k
     * @return
     */
    public boolean findTarget2(TreeNode root, int k) {
        if (root == null) {
            return false;
        }
        if (set.contains(k - root.val)) {
            return true;
        } else {
            set.add(root.val);
        }
        return findTarget2(root.left, k) || findTarget2(root.right, k);
    }

    /**
     * 广度搜索+哈希表
     *
     * @param root
     * @param k
     * @return
     */
    public boolean findTarget3(TreeNode root, int k) {
        Set<Integer> set = new HashSet<>();
        Deque<TreeNode> queue = new ArrayDeque<>();
        queue.addLast(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            while (size-- > 0) {
                TreeNode curNode = queue.pollFirst();
                if (set.contains(k - curNode.val)) {
                    return true;
                } else {
                    set.add(curNode.val);
                }
                if (curNode.left != null) {
                    queue.addLast(curNode.left);
                }
                if (curNode.right != null) {
                    queue.addLast(curNode.right);
                }
            }
        }
        return false;
    }

}
